﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace QueueSimulator
{
    public partial class Form1 : Form
    {
        private Thread SimulatorThread { get; set; }

        public Form1()
        {
            InitializeComponent();

        }

        private void runButton_Click(object sender, EventArgs e)
        {
            var q1 = new Queue(int.Parse(arrival1MinTextBox.Text), int.Parse(arrival1MaxTextBox.Text), int.Parse(service1MinTextBox.Text), int.Parse(service1MaxTextBox.Text), int.Parse(servers1TextBox.Text), int.Parse(capacity1TextBox.Text));
            var q2 = new Queue(double.Parse(arrival2PercentageTextBox.Text), int.Parse(service2MinTextBox.Text), int.Parse(service2MaxTextBox.Text), int.Parse(servers2TextBox.Text), int.Parse(capacity2TextBox.Text));

            var sim = new Simulator(q1, q2);
            sim.OnEventLogChanges += UpdateForm;

            SimulatorThread = new Thread(new ThreadStart(sim.Run));

            SimulatorThread.Start();
        }

        delegate void UpdateFormCallback(List<Event> list, Queue q1, Queue q2);

        private void UpdateForm(List<Event> list, Queue q1, Queue q2)
        {
            if (this.eventLogDataGrid.InvokeRequired)
            {
                UpdateFormCallback d = new UpdateFormCallback(UpdateForm);
                this.Invoke(d, new object[] { list, q1, q2 });
            }
            else
            {
                try
                {
                    this.eventLogDataGrid.DataSource = null;
                    this.eventLogDataGrid.DataSource = list;
                    this.eventLogDataGrid.FirstDisplayedScrollingRowIndex = list.Count - 1;

                    this.size1TextBox.Text = q1.Size.ToString();
                    this.size2TextBox.Text = q2.Size.ToString();

                    this.stats1DataGrid.DataSource = null;
                    this.stats1DataGrid.DataSource = q1.Statistics;

                    this.stats2DataGrid.DataSource = null;
                    this.stats2DataGrid.DataSource = q2.Statistics;

                    this.stats1DataGrid.Columns[0].Width = 35;
                    this.stats1DataGrid.Columns[1].Width = 50;
                    this.stats1DataGrid.Columns[2].Width = 50;

                    this.stats2DataGrid.Columns[0].Width = 35;
                    this.stats2DataGrid.Columns[1].Width = 50;
                    this.stats2DataGrid.Columns[2].Width = 50;

                    this.iterationTextBox.Text = Simulator.Iterations.ToString();
                    this.totalTimeTextBox.Text = Simulator.TotalTime.ToString();
                }
                catch
                {
                    //Swallow it :P
                }
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            SimulatorThread.Abort();
        }

        private void generateButton_Click(object sender, EventArgs e)
        {
            int size = (int.Parse(capacity1TextBox.Text) + 1) * (int.Parse(capacity2TextBox.Text) + 1);
            double[,] matrix = new double[size, size];

            Random rand = new Random();

            int cliQ1 = 0, cliQ2 = 0;

            for (int x = 0; x < size; x++)
            {
                for (int y = 0; y < size; y++)
                {
                    if (x == y)
                    {
                        continue;
                    }
                    else if (x < y)
                    {
                        if (y - x == 3) //arrival queue 1
                        {
                            matrix[x, y] = Math.Round(rand.Next(int.Parse(arrival1MinTextBox.Text), int.Parse(arrival1MaxTextBox.Text)), 2);
                        }
                        else
                            matrix[x, y] = 0;
                    }
                    else
                    {
                        if (x - y == 1 && (x % 3 != 0 || y == 0))//departure queue 2
                        {
                            matrix[x, y] = Math.Round(rand.Next(int.Parse(service2MinTextBox.Text), int.Parse(service2MaxTextBox.Text)), 2);

                            //multiplica pelo numero de servidores disponiveis para os clientes
                            matrix[x, y] *= Math.Min(cliQ2, int.Parse(servers2TextBox.Text));

                        }
                        else if (x - y == 2 && (y % 3 != 0))//departure 1 and arrival 2
                        {
                            matrix[x, y] = Math.Round(double.Parse(arrival2PercentageTextBox.Text) * rand.Next(int.Parse(service1MinTextBox.Text), int.Parse(service1MaxTextBox.Text)), 2);

                            //multiplica pelo numero de servidores disponiveis para os clientes
                            matrix[x, y] *= Math.Min(cliQ1, int.Parse(servers1TextBox.Text));
                        }
                        else if (x - y == 3) //departure queue 1
                        {
                            matrix[x, y] = Math.Round((1 - double.Parse(arrival2PercentageTextBox.Text)) * rand.Next(int.Parse(service1MinTextBox.Text), int.Parse(service1MaxTextBox.Text)), 2);

                            //multiplica pelo numero de servidores disponiveis para os clientes
                            matrix[x, y] *= Math.Min(cliQ1, int.Parse(servers1TextBox.Text));
                        }
                        else
                            matrix[x, y] = 0;
                    }
                }

                if (++cliQ2 % (int.Parse(capacity1TextBox.Text) + 1) == 0)
                {
                    cliQ1++;
                    cliQ2 = 0;
                }
            }

            double acc = 0;

            for (int x = 0; x < size; x++)
            {
                acc = 0;

                for (int y = 0; y < size; y++)
                {
                    if (x != y)
                        acc += matrix[x, y];
                }
                
                matrix[x, x] = acc;
            }

            markovDataGridView.Columns.Clear();
            markovDataGridView.Rows.Clear();

            //visualization
            for (int x = 0; x < size; x++)
            {
                markovDataGridView.Columns.Add(x.ToString(), x.ToString());
                markovDataGridView.Columns[x].Width = 40;
            }

            for (int x = 0; x < size; x++)
            {
                markovDataGridView.Rows.Add(x.ToString(), x.ToString());
            }

            for (int x = 0; x < size; x++)
            {
                for (int y = 0; y < size; y++)
                {
                    markovDataGridView[y,x].Value = matrix[x,y];
                }
            }

            
        }
    }
}
